(define (make-semaphore n)
  (let ((lock (make-mutex))
        (taken 0))
    (define (semaphore m)
      (cond ((eq? m 'acquire)
             (if (< taken n)
                 (begin (set! taken (+ 1 taken))
                        (lock 'release))
                 (begin (lock 'release)
                        (semaphore 'acquire))))
            ((eq? m 'release)
             (lock 'acquire)
             (set! taken (- taken 1))
             (lock 'release))))
    semaphore))

(define (make-semaphore-2 n)
  (let ((cell (list false))
        (taken n))
    (define (semaphore m)
      (cond ((eq? m 'require)
             (if (not (test-and-set! cell))
                 (if (< taken n)
                     (begin (set! (taken (+ 1 taken)))
                            (clear! cell))
                     (begin (clear! cell)
                            (semaphore 'require)))))
            ((eq? m 'release)
             (if (not (test-and-set! cell))
                 (begin (set! taken (- taken 1))
                        (clear! cell))))))
    semaphore))